package com.zxing.practice.service.system;

import com.mybatisflex.core.query.QueryWrapper;
import com.zxing.practice.config.SysConstant;
import com.zxing.practice.config.UserDetailsServiceImpl;
import com.zxing.practice.config.vo.LoginInfo;
import com.zxing.practice.config.vo.LoginUser;
import com.zxing.practice.entity.system.table.RolePermissionEntityTableDef;
import com.zxing.practice.entity.system.table.SysRoleEntityTableDef;
import com.zxing.practice.mapper.system.SysRolePermissionMapper;
import com.zxing.practice.vo.system.LoginBody;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class LoginService {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private SysRolePermissionMapper rolePermissionMapper;
    public String login(LoginBody loginBody) {
        String phone = loginBody.getUname();
        String password = loginBody.getPwd();
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(phone, password);
        // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        LoginUser loginUser = (LoginUser)authentication.getPrincipal();
        String username = loginUser.getUsername();
        Set<String> roleSigns = loginUser.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
        QueryWrapper permissionQuery = QueryWrapper.create().select(RolePermissionEntityTableDef.ROLE_PERMISSION_ENTITY.PERMISSION)
                .from(RolePermissionEntityTableDef.ROLE_PERMISSION_ENTITY)
                .join(SysRoleEntityTableDef.SYS_ROLE_ENTITY).on(RolePermissionEntityTableDef.ROLE_PERMISSION_ENTITY.ROLE_ID.eq(SysRoleEntityTableDef.SYS_ROLE_ENTITY.ID))
                .where(SysRoleEntityTableDef.SYS_ROLE_ENTITY.SIGN.in(roleSigns));
        List<String> permissions = rolePermissionMapper.selectObjectListByQueryAs(permissionQuery, String.class);
        long currentTime = System.currentTimeMillis();
        LoginInfo loginInfo = new LoginInfo();
        loginInfo.setExpireTime(currentTime + SysConstant.MILLIS_MINUTE_ONE_HUNDRED_EIGHT);
        loginInfo.setRoleSigns(roleSigns);
        loginInfo.setPermissions(new HashSet<>(permissions));
        redisTemplate.opsForValue().set(SysConstant.TOKEN_KEY_HEADER + username, loginInfo, SysConstant.ONE_HUNDRED_EIGHT, TimeUnit.MINUTES);
        Map<String, Object> claims = new HashMap<>();
        claims.put(SysConstant.TOKEN_KEY, username);
        return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, SysConstant.LOGIN_SECRET).compact();
    }
}
